#include "can_drv.h"
#include "processor.h"
#include <xmc_gpio.h>
#include "../xmc4500/io.h"
#include "../can/can_open.h"

#define CAN_MIN_BAUD  CAN_10KBAUD
#define CIA_CAN_BIT_SAMPLE (int) (0.875 * 16)

#define TRAC_NODE_ID 0x701

// Panel Commands f?r den Panel Controller
#define fca_PANEL_NO_OP                0   ///< No Operation
#define fca_PANEL_INIT_LIST            1   ///< Initialize Lists
#define fca_PANEL_STAT_ALLOC_MSG       2   ///< Static Allocate
#define fca_PANEL_DYN_ALLOC_MSG        3   ///< Dynamic Allocate
#define fca_PANEL_STAT_INSERT_BEFORE   4   ///< Static Insert Before
#define fca_PANEL_DYN_INSERT_BEFORE    5   ///< Dynamic Insert Before
#define fca_PANEL_STAT_INSERT_BEHIND   6   ///< Static Insert Behind
#define fca_PANEL_DYN_INSERT_BEHIND    7   ///< Dynamic Insert Behind

#define CAN_FREQUENCY                  120000000l
#define CAN_EXT_RX_PIN                 P2_6
#define CAN_EXT_TX_PIN                 P2_7
#define fls_PLACE_IN_RAM __attribute__ ((optimize(3), section(".ram_code")))

/* CAN System baud rate selectors
*-------------------------------
* -These constants are used to lookup the baud rate in the btr[] array.
*/
enum can_baud_rates
{
    CAN_10KBAUD = -4, // -4
    CAN_20KBAUD,      // -3
    CAN_50KBAUD,      // -2
    CAN_100KBAUD,     // -1
    CAN_125KBAUD,     //  0
    CAN_250KBAUD,     //  1
    CAN_500KBAUD,     //  2
    CAN_800KBAUD,     //  3
    CAN_1000KBAUD,    //  4
    CAN_BAD_BAUD
};
/*===========================================================================
   local variable                                                        */

s16 can_baud_rate;
s16 can_sample_point;
s16 can_sjw;
s16 TSeg1;
s16 TSeg2;
s16 SJW;

s16 can_message_received;           /* CAN Message buffer has received data*/
s16 CAN_Error_Count_Transmit;
s16 CAN_Error_Count_Receive;
s16 CAN_Error_LEC;
s16 mailbox_assigned[NO_OF_CAN_MAILBOXES];

CAN_MO_TypeDef *can_mo = ((CAN_MO_TypeDef *)CAN_MO0_BASE);
XMC_CAN_NODE_t *can_node_ext = ((XMC_CAN_NODE_t *)CAN_NODE1_BASE);
XMC_CAN_NODE_t *can_node_mcu = ((XMC_CAN_NODE_t *)CAN_NODE0_BASE);


/* CAN message */
XMC_CAN_MO_t CAN1_message =
{
  .can_mo_ptr = CAN_MO63,
  .can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
  .can_identifier = 0xff,
  .can_id_mask = 0x1fffffff,
  .can_id_mode = XMC_CAN_FRAME_TYPE_STANDARD_11BITS,
  .can_ide_mask = 1,
  .can_data_length = 2,
  .can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ
};

/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_125K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 125000,
  .sample_point = 8000,
  .sjw = 1,
};


/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_250K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 250000,
  .sample_point = 8000,
  .sjw = 1,
};

/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_500K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 500000,
  .sample_point = 8000,
  .sjw = 1,
};

/* CAN Bit time */
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t baud_1000K = 
{
  .can_frequency = CAN_FREQUENCY,
  .baudrate = 1000000,
  .sample_point = 8000,
  .sjw = 1,
};



/*===========================================================================
  globale Funktionen                                                       */


//--------------------------------------------------------------
/// \brief add_to_can_list
/// Allocate message object ot a list
/// \param[in]  list_no     list no.
/// \param[in]  mailbox_no  mailbox no.
/// \return void
//--------------------------------------------------------------

void add_to_can_list(s16 list_no, s16 mailbox_no)
{
    while (CAN->PANCTR & CAN_PANCTR_BUSY_Msk);
	CAN->PANCTR = ((((s32)list_no + 1) & 7) << 24) | (((s32)mailbox_no & 63) << 16) | 2;
	while (CAN->PANCTR & CAN_PANCTR_BUSY_Msk);
}

//--------------------------------------------------------------
/// \brief set_up_interrupt_node
/// Setup transmit interrupt node pointer
/// \param[in]  mailbox_no  mailbox_no
/// \param[in]  node        no pointer
/// \return void
//--------------------------------------------------------------

void set_up_interrupt_node(s16 mailbox_no, s16 node)
{
	WR_REG(can_mo[mailbox_no].MOIPR, CAN_MO_MOIPR_TXINP_Msk, CAN_MO_MOIPR_TXINP_Pos, node);
}
//--------------------------------------------------------------
/// \brief clear_newdat
/// Reset new data
/// \param[in]  mailbox_no  mailbox_no
/// \return void
//--------------------------------------------------------------

void clear_newdat(s16 mailbox_no)
{
	can_mo[mailbox_no].MOCTR = BIT3;
}

//--------------------------------------------------------------
/// \brief can_hardware_init
/// Initialize can hardware
/// \return void
//--------------------------------------------------------------

void can_hardware_init(void)
{
    /*Configure CAN Module*/
    XMC_CAN_Init(CAN, CAN_FREQUENCY);

    /*Configure CAN Node baudrate*/
    XMC_CAN_NODE_NominalBitTimeConfigure(can_node_ext, &baud_500K);
    
    XMC_CAN_NODE_EnableConfigurationChange(can_node_ext);
    XMC_CAN_NODE_SetInitBit(can_node_ext);

    /*CAN.N1_RxDD*/
    XMC_GPIO_SetMode(CAN_EXT_RX_PIN, XMC_GPIO_MODE_INPUT_TRISTATE);
	/* Configure CAN NODE input pin */
    XMC_CAN_NODE_SetReceiveInput(can_node_ext, XMC_CAN_NODE_RECEIVE_INPUT_RXDCA);

    /*Message Configuration*/
    XMC_CAN_MO_Config(&CAN1_message);
	
    /*Allocate MO in Node List*/
    XMC_CAN_AllocateMOtoNodeList(CAN, CAN_PORT_EXT, 63);
    CAN->MSIMASK = 0xffffffff;

    XMC_CAN_NODE_DisableConfigurationChange(can_node_ext);
    XMC_CAN_NODE_ResetInitBit(can_node_ext);

    /*CAN.N1_TxD*/
    XMC_GPIO_SetMode(CAN_EXT_TX_PIN, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
    canopen_init();
    
}

//--------------------------------------------------------------
/// \brief can_hardware_test_tic
/// can hardware test tic
/// \return void
//--------------------------------------------------------------

void can_hardware_test_tic(void)
{
	can_mailbox mailbox;

	mailbox.store.u32data[0] = 0x12132242;
	mailbox.store.u32data[1] = 0x62189272;
	mailbox.dlc = 8;
	mailbox.extended = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS;
	mailbox.id.full = 0x1234567;
	mailbox.port = CAN_PORT_EXT;
	send_can_message(&mailbox);
	
	mailbox.dlc = 8;
	mailbox.store.u32data[0] = 0x12345678;
	mailbox.store.u32data[1] = 0x87654321;
	mailbox.extended = XMC_CAN_FRAME_TYPE_STANDARD_11BITS;
	mailbox.id.full = 0x345;
	send_can_message(&mailbox);
	
	mailbox.dlc = 8;
	mailbox.store.u32data[0] = 0x22334455;
	mailbox.store.u32data[1] = 0x66778899;
	mailbox.extended = XMC_CAN_FRAME_TYPE_STANDARD_11BITS;
	mailbox.id.full = 0x125;
	send_can_message(&mailbox);
	return;
}
//--------------------------------------------------------------
/// \brief can_got_a_message
/// Check to see if a mailbox has received a message and return the mailbox no
/// \return value s16, -1 fail, otherwise mail box number
//--------------------------------------------------------------

s16 can_got_a_message(void)
{
	s16 msb_set = -1;					  /* return value if no pending messages*/

	if ((CAN->MSID[0] & 0x20) == 0)		  /* nothing pending if == 32*/
	{
		msb_set = CAN->MSID[0];
 		CAN->MSPND[0] &= ~(1 << msb_set);
	}
	else if ((CAN->MSID[1] & 0x20) == 0)  /* nothing pending if == 32*/
	{
		msb_set = CAN->MSID[1];
 		CAN->MSPND[1] &= ~(1 << msb_set);
		msb_set += 32;					  /* Add 32, because 2nd set of 32 mailboxes*/
	}
    
	return(msb_set);
}

void set_up_pending_flag(s16 mailbox_no)
{
	// Set up the pending bit for the mailbox, we sequentially allocate these in ascending order for the mailbox
	WR_REG(can_mo[mailbox_no].MOIPR, CAN_MO_MOIPR_MPN_Msk, CAN_MO_MOIPR_MPN_Pos, mailbox_no);
}


//--------------------------------------------------------------
/// \brief setup_receive_mailbox
/// Check to see if a mailbox has received a message and return the mailbox no
/// \param[in]  port              can port
/// \param[in]  mailbox_no        mailbox number
/// \param[in]  acceptance_id     acceptance id
/// \param[in]  acceptance_mask   acceptance mask
/// \param[in]  extended          extended
/// \return value s16, 0 fail,   otherwise mail box number
//--------------------------------------------------------------
static s16 setup_receive_mailbox(s8 port, s16 mailbox_no, s32 acceptance_id)
{
	if (mailbox_assigned[mailbox_no])
	{  
		can_mo[mailbox_no].MOCTR   = 0x00A00000;	// load MO control register, Receive mailbox, and enable receive
		can_mo[mailbox_no].MOFCR   = 0x08010000;	// load MO function control register
		can_mo[mailbox_no].MOFGPR  = 0x00000000;	// load MO FIFO/gateway pointer register
		can_mo[mailbox_no].MOIPR   = 0x00000000;	// load MO1 interrupt pointer register
		set_up_pending_flag(mailbox_no);			// Allocate the pending bit for the mailbox, so we can recognize the recieve source
		set_up_interrupt_node(mailbox_no, port);		// All reveive message interrupts on node 0
		can_mo[mailbox_no].MOCTR   = 0x00200000;	// set MSGVAL
		can_mo[mailbox_no].MOAMR = 0x20000000 | (((CAN_11_BIT_MASK & CAN_11_BIT_MASK) << 2 ) << 16);		// load MO acceptance mask register
		can_mo[mailbox_no].MOAR = 0x80000000 | (((acceptance_id & CAN_11_BIT_MASK) << 2 ) << 16);		// ID
		XMC_CAN_AllocateMOtoNodeList(CAN, port, mailbox_no);
		return(1);
	}
	else
    {   
		return(0);
    }
}

s16 mailbox_vInit(s8 port, s32 acceptance_id)
{
    s16 mail_box = assign_a_mailbox(port);

    if(mail_box > -1)
    {
        setup_receive_mailbox(port, mail_box, acceptance_id);
        return 0;
    }
    return -1;
}

void set_mailbox_assigned_flag(s16 mailbox_no)
{
	mailbox_assigned[mailbox_no] = 1;
}



//--------------------------------------------------------------
/// \brief receive_can_messages_tic
/// Receive can messages and place in the received message FIFO.
/// \param[in]  void
/// \return     void
//--------------------------------------------------------------
void receive_can_messages_tic(void)
{
	s16 mailbox_no;
	
	/*check for new messages*/
	
	while ((mailbox_no = can_got_a_message()) >= 0)
	{
		can_received_messages.mail_box[can_received_messages.in_ptr++] = mailbox_no;
		if (can_received_messages.in_ptr >= MESSAGE_RECEIVED_BUFFER_SIZE)
        {      
			can_received_messages.in_ptr = 0;
        }
		
		/* mailbox_no needs to be saved with the message so it knows where it came from, for back referencing */
		can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].mailbox_no = mailbox_no;
		can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].port = can_message[mailbox_no].port;
		if (can_mo[mailbox_no].MOAR & BIT29)					/* check for extended id */
        {      
			can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].id.full = can_mo[mailbox_no].MOAR & CAN_29_BIT_MASK;
        }
		else
        {      
			can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].id.full = (can_mo[mailbox_no].MOAR >> 18) & CAN_11_BIT_MASK;
        }
		can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].store.u32data[0] = can_mo[mailbox_no].MODATAL;
		can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].store.u32data[1] = can_mo[mailbox_no].MODATAH;
		can_message[mailbox_no].buffer.mailbox[can_message[mailbox_no].buffer.in_ptr].dlc =(can_mo[mailbox_no].MOFCR >> 24) & 0x0f;
		clear_newdat(mailbox_no);
		if (++can_message[mailbox_no].buffer.in_ptr >= CAN_BUFFER_SIZE)
        {      
			can_message[mailbox_no].buffer.in_ptr = 0;
        }
	}
}

//--------------------------------------------------------------
/// \brief transmit_can_messages
/// Low level routine to tranmit the pending messages in the transmit FIFO
/// \param[in]  port which port to transmit
/// \return     void
//--------------------------------------------------------------
void transmit_can_messages_ext(void)
{
    can_mailbox* box_out;
    
	if (can_transmit_message[CAN_PORT_EXT].in_ptr != can_transmit_message[CAN_PORT_EXT].out_ptr)
	{
        box_out = &(can_transmit_message[CAN_PORT_EXT].buffer[can_transmit_message[CAN_PORT_EXT].out_ptr]);
        CAN1_message.can_data_length = box_out->dlc;
        CAN1_message.can_id_mode = box_out->extended;
        CAN1_message.can_data[0] = box_out->store.u32data[0];
        CAN1_message.can_data[1] = box_out->store.u32data[1];
        CAN1_message.can_identifier = box_out->id.full;
        XMC_CAN_MO_Config(&CAN1_message);
        /*Send message*/
        XMC_CAN_MO_Transmit(&CAN1_message);
		if (++can_transmit_message[CAN_PORT_EXT].out_ptr >= NO_OF_TRANSMIT_BUFFERS)
        {      
			can_transmit_message[CAN_PORT_EXT].out_ptr = 0;
        }
	}
}



fls_PLACE_IN_RAM void send_can_message_hw(can_mailbox *mailbox)
{
    CAN1_message.can_mo_ptr->MOCTR = 0x00000020;
    CAN1_message.can_mo_ptr->MODATAL = (*mailbox).store.u32data[0];
    CAN1_message.can_mo_ptr->MODATAH = (*mailbox).store.u32data[1];
    CAN1_message.can_mo_ptr->MOCTR = 0x07280040;
}


